package club.jdiy.dev.zlt.controller;

import club.jdiy.admin.SystemConfig;
import club.jdiy.admin.controller.JDiyAdminCtrl;
import club.jdiy.admin.entity.Dict;
import club.jdiy.admin.interceptor.GuestDisabled;
import club.jdiy.core.base.domain.Ret;
import club.jdiy.core.sql.TableInfo;
import club.jdiy.core.storage.Store;
import club.jdiy.dev.controller.JDiyController;
import club.jdiy.dev.zlt.service.JDevDictService;
import club.jdiy.utils.DateUtils;
import club.jdiy.utils.StringUtils;
import club.jdiy.dev.zlt.utils.POIWordUtil;
import lombok.Data;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Controller
@RequestMapping("mgmt/JDiyAdmin")
public class JDevEtcCtrl extends JDiyAdminCtrl<Dict, JDevDictService> implements JDiyController {
    @GetMapping(path = "etc.dbDict")
    public String dbDict(ModelMap map) {
        map.put("tables", context.getDao().getTables());
        map.put("jdiy", context.getConfig(SystemConfig.class));
        return "db.doc";
    }

    @GetMapping("etc.settings")
    public String settings(ModelMap map) {
        map.put("vo", context.getConfig(SystemConfig.class));
        return "settings";
    }

    @ResponseBody
    @GuestDisabled
    @PostMapping("etc.settings")
    public Ret<String> settings(SystemConfig qo, MultipartFile[] loginBg) throws Exception {
        context.saveConfig(qo);
        Store store = context.getStore("system", "jdiy");
        for (MultipartFile mf : loginBg) {
            store.add("loginBg", mf);
        }
        //防止因修改单端登录，导致当前用户会话失效：
        context.setCookie("userToken", context.getCurrentUser().token(context.getConfig(SystemConfig.class).isSingleLoginOn()));
        return Ret.success();
    }
    @GetMapping(path = "etc.api")
    public String api(ModelMap map) {
        return "api";
    }

    @PostMapping("etc.dbDict")
    @ResponseBody
    public void dbDict(String[] tables, HttpServletResponse response, HttpServletRequest request,
                       String project,
                       String version, String createTime,
                       String developer, String author) throws Exception {
        if (StringUtils.isEmpty(project)) project = context.getConfig().get("id");
        final List<String> includeTableNames = tables == null ? new ArrayList<>() : Arrays.asList(tables);
        final List<TableInfo> tableList = context.getDao().getTables().stream()
                .filter(t -> includeTableNames.contains(t.getName()))
                .collect(Collectors.toList());

        XWPFDocument doc = new XWPFDocument();

        //创建三个标题样式：
        XWPFStyles styles = doc.createStyles();
        POIWordUtil.addCustomHeadingStyle(styles, "Heading1", 1, 36);
        POIWordUtil.addCustomHeadingStyle(styles, "Heading2", 2, 30);
        POIWordUtil.addCustomHeadingStyle(styles, "Heading3", 3, 24);

        //设置标题
        POIWordUtil.setTitle(doc, project + " 数据库字典文档", 20, ParagraphAlignment.CENTER);
        //版本&日期：
        POIWordUtil.newParagraphText(doc,
                "版本：" + (StringUtils.hasText(version) ? version : "1.0") + "　日期："
                        + (StringUtils.hasText(createTime) ? createTime : DateUtils.fmt_date.format(LocalDate.now())),
                ParagraphAlignment.CENTER);
        //换行3
        POIWordUtil.nextLine(doc, 3);

        POIWordUtil.createLevel(doc, "Heading1", ParagraphAlignment.CENTER, "4288BC", 18, "一、数据库表概览", true);
        POIWordUtil.nextLine(doc, 1);

        XWPFTable table1 = POIWordUtil.createTable(doc, tableList.size() + 1, 3);
        XWPFTableRow rowHeader1 = table1.getRow(0);
        POIWordUtil.setTableCellHeader(rowHeader1, 0, "序号", "2000");
        POIWordUtil.setTableCellHeader(rowHeader1, 1, "表名", "3000");
        POIWordUtil.setTableCellHeader(rowHeader1, 2, "注释/说明", "5000");


        IntStream.range(0, tableList.size()).forEach(i -> {
            TableInfo m = tableList.get(i);
            XWPFTableRow row = table1.getRow(i + 1);
            POIWordUtil.setTableCell(row, 0, String.valueOf(i + 1), "2000");
            POIWordUtil.setTableCell(row, 1, m.getName(), "3000");
            POIWordUtil.setTableCell(row, 2, m.getComment(), "5000");
        });

        POIWordUtil.nextLine(doc, 2);
        POIWordUtil.createLevel(doc, "Heading1", ParagraphAlignment.CENTER, "4288BC", 18, "二、数据库表结构", true);
        POIWordUtil.nextLine(doc, 1);

        int bound = tableList.size();
        for (int k = 0; k < bound; k++) {
            TableInfo m = tableList.get(k);
            String table_name = m.getName();
            String table_comment = m.getComment();

            Collection<club.jdiy.core.sql.ColumnInfo> columnList = context.getDao().getColumns(table_name).values();

            String tableNameStr = table_name;
            if (!StringUtils.isEmpty(table_comment)) {
                tableNameStr += "【" + table_comment + "】";
            }

            POIWordUtil.createLevel(doc, "Heading2", ParagraphAlignment.LEFT, "4288BC", 16,
                    (k + 1) + "、 " + tableNameStr, true);

            //创建指定行列的表格
            XWPFTable table = POIWordUtil.createTable(doc, columnList.size() + 1, 5);

            //设置表头，列宽
            XWPFTableRow rowHeader = table.getRow(0);
            __columnHeader(0, rowHeader, "字段名", 15);
            __columnHeader(1, rowHeader, "数据类型", 15);
            __columnHeader(2, rowHeader, "允许为空", 15);
            __columnHeader(3, rowHeader, "默认值", 15);
            __columnHeader(4, rowHeader, "字段说明", 30);


            //插入单元格文本
            int i1 = 1;
            for (club.jdiy.core.sql.ColumnInfo cm : columnList) {
                XWPFTableRow row = table.getRow(i1++);
                __columnBody(0, row, cm.getName(), 15, false);
                __columnBody(1, row, cm.getType(), 15, false);
                __columnBody(2, row, cm.isNullable() ? "是" : "否", 15, false);
                __columnBody(3, row, cm.getDefaultValue(), 15, false);
                __columnBody(4, row, cm.getComment(), 30, cm.isPrimaryKey());
            }
            POIWordUtil.nextLine(doc, 1);
        }

        POIWordUtil.nextLine(doc, 2);
        if (StringUtils.hasText(developer) || StringUtils.hasText(author)) {
            if (StringUtils.hasText(developer)) POIWordUtil.newParagraphText(doc, developer, ParagraphAlignment.RIGHT);
            if (StringUtils.hasText(author))
                POIWordUtil.newParagraphText(doc, "编辑：" + author, ParagraphAlignment.RIGHT);
        } else {
            POIWordUtil.newParagraphText(doc, "(全文　完)", ParagraphAlignment.CENTER);
        }

        OutputStream out = response.getOutputStream();
        response.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        response.setHeader("Content-Disposition", "attachment; filename="
                + getFileName(request, project + "-数据库字典文档.docx"));
        doc.write(out);
    }

    private String getFileName(HttpServletRequest request, String name) throws UnsupportedEncodingException {
        String userAgent = request.getHeader("USER-AGENT");
        return userAgent.contains("Mozilla")
                ? new String(name.getBytes(), "ISO8859-1")
                : new String(name.getBytes("gb2312"), "iso8859-1");
    }


    private static void __columnHeader(int colIndex, XWPFTableRow rowHeader, String text, double widthPst) {
        String width = (int) (9000 * (widthPst / 90)) + "";
        POIWordUtil.setTableCellHeader(rowHeader, colIndex, text, width);
    }

    private static void __columnBody(int colIndex, XWPFTableRow row, String cellVal, double widthPst, boolean commentPk) {
        if (commentPk && (cellVal == null || !cellVal.contains("主键"))) {
            if (cellVal == null) cellVal = "「主键」";
            else cellVal = "「主键」 " + cellVal;
        }
        String width = (int) (9000 * (widthPst / 90)) + "";
        POIWordUtil.setTableCell(row, colIndex, cellVal, width);
    }

    @Data
    public static class ColumnInfo {
        private String desc; //描述
        private int widthPercent; //宽度占比以0~100的数字表示

        public ColumnInfo(String desc, int widthPercent) {
            this.desc = desc;
            this.widthPercent = widthPercent;
        }
    }
}